﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tracy.DataModel;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using SharedLib.Helpers;
using Tracy.Messages;
using SharedLib.MessageFramework;
using SharedLib;
using SharedLib.MessageFramework.Messages;
using Tracy.DataModel.SourceParser;
namespace Tracy.Plugins.SourceParsers
{
    public class XSLTSourceParser : ISourceParser
    {
        public event EventHandler<GenericEventArgs<SourceParserResult>> OnResultFound;
        public event EventHandler<GenericEventArgs<SourceEntryPair>> OnParseCompleted;
        static Dictionary<string, System.Xml.Xsl.XslCompiledTransform> _cachedXslTransforms = new Dictionary<string, System.Xml.Xsl.XslCompiledTransform>();
        private object _lockHelperXSLTCache = new object();
        private XmlDocument GetRawResources(XmlDocument doc, FeedSource source)
        {
            if (source != null)
            {
                string xsltMapping = source.Properties["mapping"];
                if (String.IsNullOrEmpty(xsltMapping)) throw new Exception("Mapping not found in feedsource");//TODO: Config Exception here
                XslCompiledTransform xslt;
                lock (_lockHelperXSLTCache)
                {
                    if (!_cachedXslTransforms.ContainsKey(xsltMapping))
                    {
                        xslt = new XslCompiledTransform();
                        xslt.Load(xsltMapping);
                        _cachedXslTransforms.Add(xsltMapping, xslt);
                    }
                    else
                    {
                        xslt = _cachedXslTransforms[xsltMapping];
                    }
                }
                return XmlHelper.PerformXslTrasform(doc, xslt);
            }
            return null;
        }

        
        #region URL-FeedSource-Entry dict
        Dictionary<MessageData<string>, SourceEntryPair> _urlDict = new Dictionary<MessageData<string>, SourceEntryPair>();
        private object _lockHelperDict = new object();
        private void AddDictItem(MessageData<string> url, FeedSource source, Entry entry)
        {
            lock (_lockHelperDict)
            {
                _urlDict.Add(url, new SourceEntryPair() { Entry = entry, Source = source });
            }
        }

        private void RemoveDictItem(MessageData<string> url)
        {
            lock (_lockHelperDict)
            {
                _urlDict.Remove(url);
            }
        }

        private SourceEntryPair GetDictItem(MessageData<string> url)
        {
            lock (_lockHelperDict)
            {
                return _urlDict[url];
            }
        }
        #endregion

        public void Parse(FeedSource source, Entry entry)
        {
            if (source != null && entry != null)
            {
                string url = source.GenerateUrl(entry);
                MessageData<string> urlData = new MessageData<string>(url);
                AddDictItem(urlData, source, entry);
                GetXmlFromURLMessage msg = new GetXmlFromURLMessage(this, urlData, "GetXmlFromURLHandler_KTXP");
                msg.CallBack = OnXmlRetrieved;
                TracyFacade.Instance.MessageDispatcher.EnqueueMessage(msg);
            }
        }

        private void OnXmlRetrieved(IAppMessage msg)
        {
            if (msg != null && msg is GetXmlFromURLMessage && !msg.CancelFlag)
            {
                if (msg.Exception == null)
                {
                    MessageData<string> url = msg.Data as MessageData<string>;
                    SourceEntryPair pair = GetDictItem(url);
                    Entry entry = pair.Entry;
                    FeedSource source = pair.Source;
                    RemoveDictItem(url);

                    XmlDocument doc = msg.Result as XmlDocument;
                    XmlDocument resultDoc = GetRawResources(doc, source);

                    //Notify Caller
                    if (resultDoc.SelectNodes("result/resource").Count > 0)
                    {
                        if (OnResultFound != null) OnResultFound.InvokeEvent(this, new GenericEventArgs<SourceParserResult>(new SourceParserResult() { ResultDoc = resultDoc, Source = source, Entry = entry }));                        
                    }
                    if (OnParseCompleted != null) OnParseCompleted.InvokeEvent(this, new GenericEventArgs<SourceEntryPair>(new SourceEntryPair() { Source = source, Entry = entry }));
                }
                else
                {
                    //TODO: Exception
                }
            }
        }
    }
}
